<template>
  <div id="app"></div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import "./libs/onEvent";
import Stats from "stats.js";
import Storey from "./components/Storey";
import * as dat from "dat.gui";
import TWEEN from "@tweenjs/tween.js";

export default {
  name: "App",
  data() {
    return {
      scene: null,
      camera: null,
      cameraPosition: {
        x: 1800,
        y: 2700,
        z: 2700
      },
      renderer: null,
      controls: null,
      gui: null,
      stats: null,
      threeOnEvent: null,
      storeys: [] // 所有楼层
    };
  },
  mounted() {
    this.initScene();
    this.initCamera();
    this.initLights();
    this.initRenderer();
    this.initEvents();
    this.initModels();
    this.initControls();
    this.initStats();
    // this.initGUI();
    this.initHelpers();
    this.loop();
    window.addEventListener("resize", this.onWindowResize);
  },
  methods: {
    /**
     * 初始化场景
     */
    initScene() {
      this.scene = new THREE.Scene();
    },
    /**
     * 初始化相机
     */
    initCamera() {
      this.camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        10000
      );
      this.camera.position.set(
        this.cameraPosition.x,
        this.cameraPosition.y,
        this.cameraPosition.z
      );
      this.camera.lookAt(new THREE.Vector3(0, 0, 0));
    },
    /**
     * 初始化灯光
     */
    initLights() {
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3); // 模拟阳光
      directionalLight.color.setHSL(0.1, 1, 0.95);
      directionalLight.position.set(0, 200, -80).normalize(); // normalize作用：将该向量转换为单位向量（unit vector）， 也就是说，将该向量的方向设置为和原向量相同，但是其长度（length）为1。
      this.scene.add(directionalLight);
      var ambientLight = new THREE.AmbientLight(0xffffff, 0.8); // 环境光
      this.scene.add(ambientLight);
    },
    /**
     * 初始化渲染器
     */
    initRenderer() {
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      this.renderer.setClearColor(0x4682b4, 1.0);
      document.getElementById("app").appendChild(this.renderer.domElement);
    },
    /**
     * 初始化模型
     */
    initModels() {
      const floors = 5; // 楼层总数
      const floorHeight = 242; // 楼层高度
      for (let i = 0; i < floors; i += 1) {
        const storey = new Storey().mesh;
        storey.translateY(floorHeight * i);
        storey.children.forEach(mesh => {
          mesh.on("click", () => {
            // i 为当前点击的楼层序号（0开始）
            for (let m = 0; m < floors; m += 1) {
              if (m <= i) {
                // this.storeys[m].position.y = floorHeight * m;
                const position = { y: this.storeys[m].position.y };
                const tween = new TWEEN.Tween(position)
                  .to(
                    {
                      y: floorHeight * m
                    },
                    200
                  )
                  .easing(TWEEN.Easing.Sinusoidal.InOut)
                  .onUpdate(() => {
                    this.storeys[m].position.y = position.y;
                  });
                tween.start();
              } else {
                // this.storeys[m].position.y = floorHeight * m + 600;
                const position = { y: this.storeys[m].position.y };
                const tween = new TWEEN.Tween(position)
                  .to(
                    {
                      y: floorHeight * m + 600
                    },
                    200
                  )
                  .easing(TWEEN.Easing.Sinusoidal.InOut)
                  .onUpdate(() => {
                    this.storeys[m].position.y = position.y;
                  });
                tween.start();
              }
            }
          });
        });
        this.scene.add(storey);
        this.storeys.push(storey);
      }
    },
    /**
     * 初始化事件
     */
    initEvents() {
      this.threeOnEvent = new THREE.onEvent(this.scene, this.camera);
    },
    /**
     * 初始化控制器
     */
    initControls() {
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.enableDamping = true;
      this.controls.dampingFactor = 0.5;
      // 视角最小距离
      this.controls.minDistance = 100;
      // 视角最大距离
      // this.controls.maxDistance = 5000;
      // 最大角度
      // this.controls.maxPolarAngle = Math.PI / 2.2;
    },
    /**
     * 初始化监控器
     */
    initStats() {
      this.stats = new Stats();
      this.stats.setMode(0);
      document.getElementById("app").appendChild(this.stats.dom);
    },
    /**
     * 初始化界面交互插件
     */
    initGUI() {
      this.gui = new dat.GUI();
      this.gui.add(this.cameraPosition, "x", 0, 4000);
      this.gui.add(this.cameraPosition, "y", 0, 4000);
      this.gui.add(this.cameraPosition, "z", 0, 4000);
    },
    /**
     * 初始化辅助工具
     */
    initHelpers() {
      const axesHelper = new THREE.AxesHelper(2000);
      this.scene.add(axesHelper);
    },
    /**
     * 窗口大小发生变化
     */
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    },
    /**
     * 更新控件
     */
    update() {
      this.controls.update();
      this.stats.update();
      TWEEN.update();
    },
    /**
     * 循环更新视图
     */
    loop() {
      requestAnimationFrame(this.loop);
      this.update();
      this.renderer.render(this.scene, this.camera);
    }
  }
};
</script>

<style>
html,
body,
#app {
  height: 100%;
  margin: 0;
  padding: 0;
}
</style>
